Skip to content

Clarify RTSP reconnect safety and HTTP error handling for mypy#3263

Merged
MichaIng merged 24 commits intodevfrom
copilot/fix-mypy-errors
Feb 4, 2026
Merged

Clarify RTSP reconnect safety and HTTP error handling for mypy#3263
MichaIng merged 24 commits intodevfrom
copilot/fix-mypy-errors

Conversation

Copy link
Contributor

Copilot AI commented Feb 3, 2026

  • Cast handler_mapping when creating the Tornado Application to satisfy mypy’s expected Sequence type
  • Ensure mypy in active env; all checks pass
Original prompt

mypy throws a number or errors, which we currently ignore:

motioneye/utils/dtconv.py:65: error: Name "_" is not defined  [name-defined]
motioneye/utils/dtconv.py:71: error: Name "_" is not defined  [name-defined]
motioneye/utils/http.py:32: error: Argument 2 to "getattr" has incompatible type "str | Hashable"; expected "str"  [arg-type]
tests/__init__.py:23: error: Incompatible types in assignment (expression has type "None", variable has type "type")  [assignment]
motioneye/tasks.py:37: error: Need type annotation for "_tasks" (hint: "_tasks: list[<type>] = ...")  [var-annotated]
motioneye/utils/__init__.py:84: error: Incompatible types in assignment (expression has type "None", variable has type "list[Any]")  [assignment]
motioneye/utils/__init__.py:85: error: Incompatible types in assignment (expression has type "None", variable has type "str")  [assignment]
motioneye/utils/__init__.py:238: error: Incompatible types in assignment (expression has type "str", variable has type "list[tuple[Any, Any]]")  [assignment]
motioneye/remote.py:85: error: Incompatible types in assignment (expression has type "str", variable has type "BaseException | None")  [assignment]
motioneye/utils/rtsp.py:45: error: Need type annotation for "future"  [var-annotated]
motioneye/utils/rtsp.py:106: error: "None" has no attribute "read_until_regex"  [attr-defined]
motioneye/utils/rtsp.py:108: error: No overload variant of "__setitem__" of "list" matches argument types "int", "object"  [call-overload]
motioneye/utils/rtsp.py:108: note: Possible overload variants:
motioneye/utils/rtsp.py:108: note:     def __setitem__(self, SupportsIndex, None, /) -> None
motioneye/utils/rtsp.py:108: note:     def __setitem__(self, slice[Any, Any, Any], Iterable[None], /) -> None
motioneye/utils/mjpeg.py:42: error: Need type annotation for "future"  [var-annotated]
motioneye/motionctl.py:450: error: Name "has_h264_nvenc_support" already defined on line 390  [no-redef]
motioneye/motionctl.py:460: error: Name "has_h264_nvmpi_support" already defined on line 400  [no-redef]
motioneye/motionctl.py:470: error: Name "has_hevc_nvmpi_support" already defined on line 410  [no-redef]
motioneye/motionctl.py:480: error: Name "has_hevc_nvenc_support" already defined on line 420  [no-redef]
motioneye/motionctl.py:490: error: Name "has_h264_qsv_support" already defined on line 430  [no-redef]
motioneye/motionctl.py:500: error: Name "has_hevc_qsv_support" already defined on line 440  [no-redef]
motioneye/mediafiles.py:99: error: Need type annotation for "_prepared_files" (hint: "_prepared_files: dict[<type>, <type>] = ...")  [var-annotated]
motioneye/mediafiles.py:108: error: Incompatible default for argument "sub_path" (default has type "None", argument has type "str")  [assignment]
motioneye/mediafiles.py:108: note: PEP 484 prohibits implicit Optional. Accordingly, mypy has changed its default to no_implicit_optional=True
motioneye/mediafiles.py:108: note: Use https://github.com/hauntsaninja/no_implicit_optional to automatically upgrade your codebase
motioneye/mediafiles.py:419: error: Argument 3 to "_remove_older_files" has incompatible type "dict[str, Any] | None"; expected "dict[Any, Any]"  [arg-type]
motioneye/mediafiles.py:494: error: Need type annotation for "fut"  [var-annotated]
motioneye/mediafiles.py:579: error: Need type annotation for "fut"  [var-annotated]
motioneye/config.py:62: error: Need type annotation for "_camera_config_cache" (hint: "_camera_config_cache: dict[<type>, <type>] = ...")  [var-annotated]
motioneye/monitor.py:28: error: Need type annotation for "_monitor_info_cache_by_camera_id" (hint: "_monitor_info_cache_by_camera_id: dict[<type>, <type>] = ...")  [var-annotated]
motioneye/monitor.py:29: error: Need type annotation for "_last_call_time_by_camera_id" (hint: "_last_call_time_by_camera_id: dict[<type>, <type>] = ...")  [var-annotated]
motioneye/monitor.py:30: error: Need type annotation for "_interval_by_camera_id" (hint: "_interval_by_camera_id: dict[<type>, <type>] = ...")  [var-annotated]
motioneye/mjpgclient.py:35: error: Need type annotation for "clients" (hint: "clients: dict[<type>, <type>] = ...")  [var-annotated]
motioneye/mjpgclient.py:189: error: Incompatible default for argument "future" (default has type "bool", argument has type "Future[Any]")  [assignment]
motioneye/handlers/config.py:409: error: No return value expected  [return-value]
motioneye/handlers/config.py:425: error: No return value expected  [return-value]
motioneye/server.py:408: error: Argument 1 to "Application" has incompatible type "list[tuple[str | type[BaseHandler] | dict[str, str], ...]]"; expected "Sequence[Rule | list[Any] | tuple[str | Matcher, Any] | tuple[str | Matcher, Any, dict[str, Any]] | tuple[str | Matcher, Any, dict[str, Any], str]] | None"  [arg-type]
tests/test_handlers/__init__.py:16: error: Type variable "tests.test_handlers.T" is unbound  [valid-type]
tests/test_handlers/__init__.py:16: note: (Hint: Use "Generic[T]" or "Prot...

</details>



<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

Co-authored-by: MichaIng <28480705+MichaIng@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix mypy errors in several modules Reduce mypy noise with targeted typing fixes Feb 3, 2026
Copilot AI requested a review from MichaIng February 3, 2026 18:42
@MichaIng
Copy link
Member

MichaIng commented Feb 3, 2026

@copilot
Please explain why mypy was throwing error: Name "_" is not defined only for the pretty_date() method in dtconv.py, but not for pretty_date_time() and pretty_duration(), which use the function as well.

Especially pretty_duration() is like pretty_date() only called in templates.py, added to _jinja_env.filters for HTML template translations, nowhere else. So why is _ defined in pretty_duration() but not in pretty_date()?

Copy link
Contributor Author

Copilot AI commented Feb 3, 2026

@copilot
Please explain why mypy was throwing error: Name "_" is not defined only for the pretty_date() method in dtconf.py, but not for pretty_date_time() and pretty_duration(), which u...

Mypy was only checking the annotated functions. pretty_date had a typed signature (Union[datetime.date, int]), so its body was type-checked and the missing _ was reported. pretty_date_time and pretty_duration are unannotated, and with check_untyped_defs disabled they were skipped, so mypy never saw the undefined _ there. After the fix in e7e9f3f, _ is defined at module scope and the error goes away consistently.

@MichaIng
Copy link
Member

MichaIng commented Feb 3, 2026

@copilot
So _ was actually defined in all cases where dtconv functions are used across our code, and only when viewing it as independent module, it was missing?

To potentially reduce redundant processing:

  1. Remove the intermediate _gettext assignment. It seems unnecessary as you assign it to _ unconditionally anyway.
  2. Please wrap it into a conditional import gettext, motioneye.settings, and assign _ only if it is not defined yet. If have such a feeling that this mypy annotation will haunt us in every script where we call _, once we add function types. So it seems we need a cleaner solution long-term, like splitting out our translation setup into an own module, to reduce redundant code.

Co-authored-by: MichaIng <28480705+MichaIng@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 3, 2026

@copilot
So _ was actually defined in all cases where dtconv functions are used across our code, and only when viewing it as independent module, it was missing?

...

I removed the redundant _gettext binding and now only import gettext/settings and bind _ if it’s not already defined (commit 339a37e). That keeps existing translations intact when dtconv is loaded in normal runtime, while satisfying mypy when the module is checked in isolation. A shared translation helper would be a good follow-up to centralize this pattern across modules.

@MichaIng
Copy link
Member

MichaIng commented Feb 3, 2026

@copilot
Also from typing import Callable is now only needed if _ is not defined yet. Is it the fastest/cleanest check to try: it? Is it cheaper/faster to just call it, instead of checking hasattr(ClassName, 'method_name') or similar?

Co-authored-by: MichaIng <28480705+MichaIng@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 3, 2026

@copilot
Also from typing import Callable is now only needed if _ is not defined yet. Is it the fastest/cleanest check to try: it? Is it cheaper/faster to just call it, instead of checking `ha...

Adjusted: Callable now imports only inside the fallback branch so it’s not loaded when _ already exists (commit 3a3f7db). The try/except NameError is the fastest check in CPython here—no extra globals lookup or hasattr dance before accessing _; we only pay the import cost when binding it.

@MichaIng
Copy link
Member

MichaIng commented Feb 3, 2026

@copilot
pre-commit in our CI was throwing an annotition with the following diff:

diff --git a/motioneye/mediafiles.py b/motioneye/mediafiles.py
index b4ea5c3..334d302 100644
--- a/motioneye/mediafiles.py
+++ b/motioneye/mediafiles.py
@@ -105,7 +105,10 @@ _ffmpeg_binary_cache = None
 
 
 def _list_media_files(
-    base_path: str, exts: typing.List[str], sub_path: str | None = None, with_stat: bool = True
+    base_path: str,
+    exts: typing.List[str],
+    sub_path: str | None = None,
+    with_stat: bool = True,
 ) -> typing.List[tuple]:
     # Determine scan path based on sub_path parameter
     if sub_path is not None:
@@ -489,7 +492,10 @@ def make_movie_preview(camera_config: dict, full_path: str) -> typing.Union[str,
 
 
 def list_media(
-    camera_config: dict, media_type: str, prefix: str | None = None, with_stat: bool = True
+    camera_config: dict,
+    media_type: str,
+    prefix: str | None = None,
+    with_stat: bool = True,
 ) -> typing.Awaitable:
     fut: Future = Future()
     target_dir = camera_config.get('target_dir')
diff --git a/motioneye/utils/dtconv.py b/motioneye/utils/dtconv.py
index 44c4b23..189ea99 100644
--- a/motioneye/utils/dtconv.py
+++ b/motioneye/utils/dtconv.py
@@ -25,11 +25,10 @@ try:
 except NameError:
     import gettext
     from typing import Callable
+
     from motioneye import settings
 
-    _: Callable[[str], str] = getattr(
-        settings.traduction, 'gettext', gettext.gettext
-    )
+    _: Callable[[str], str] = getattr(settings.traduction, 'gettext', gettext.gettext)
 
 
 def pretty_date_time(date_time, tzinfo=None, short=False):

Please apply this.

Co-authored-by: MichaIng <28480705+MichaIng@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 3, 2026

@copilot
pre-commit in our CI was throwing an annotition with the following diff:

...

Applied the pre-commit formatting adjustments to mediafiles.py and dtconv.py as shown (commit e380428).

github-actions bot and others added 2 commits February 3, 2026 19:56
Copilot AI changed the title Make mypy pass: dedupe codec helpers, fix handler return flow, and error handling Resolve remaining mypy issues: handler flow, RTSP scoping, and HTTP error handling Feb 3, 2026
Co-authored-by: MichaIng <28480705+MichaIng@users.noreply.github.com>
Copilot AI changed the title Resolve remaining mypy issues: handler flow, RTSP scoping, and HTTP error handling Tighten RTSP stream scoping and HTTP error handling for mypy compliance Feb 3, 2026
Signed-off-by: MichaIng <micha@dietpi.com>
Co-authored-by: MichaIng <28480705+MichaIng@users.noreply.github.com>
Copilot AI changed the title Tighten RTSP stream scoping and HTTP error handling for mypy compliance Harden RTSP reconnects and HTTP error typing for mypy compliance Feb 3, 2026
Copilot AI changed the title Harden RTSP reconnects and HTTP error typing for mypy compliance Clarify RTSP reconnect safety and HTTP error handling for mypy Feb 3, 2026
@MichaIng MichaIng marked this pull request as ready for review February 3, 2026 23:02
Signed-off-by: MichaIng <micha@dietpi.com>
@MichaIng MichaIng force-pushed the copilot/fix-mypy-errors branch from e7c5740 to a803973 Compare February 3, 2026 23:43
@MichaIng
Copy link
Member

MichaIng commented Feb 3, 2026

@copilot
There is one last mypy error:

motioneye/server.py:408: error: Argument 1 to "Application" has incompatible type "list[tuple[str | type[BaseHandler] | dict[str, str], ...]]"; expected "Sequence[Rule | list[Any] | tuple[str | Matcher, Any] | tuple[str | Matcher, Any, dict[str, Any]] | tuple[str | Matcher, Any, dict[str, Any], str]] | None"  [arg-type]

Can you find a solution for this? Looking at the docs for tornado.web.Application, its accepts List[Rule | Tuple] as first argument: https://www.tornadoweb.org/en/stable/web.html#tornado.web.Application. handler_mapping is hardcoded as list of tuples in our script, so I do not see the issue. Does handler_mapping just need a List[Rule | Tuple] type definition? The type from the error seems unreasonably long to apply to the code.

Co-authored-by: MichaIng <28480705+MichaIng@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 3, 2026

@copilot
There is one last mypy error:

...

Added a minimal cast when constructing the Tornado Application so handler_mapping matches the expected Sequence type (commit 384682c).

@MichaIng MichaIng force-pushed the copilot/fix-mypy-errors branch from 716894c to e6d0e94 Compare February 4, 2026 00:09
Signed-off-by: MichaIng <micha@dietpi.com>
@MichaIng MichaIng force-pushed the copilot/fix-mypy-errors branch from e6d0e94 to 7d70f91 Compare February 4, 2026 00:16
@MichaIng MichaIng merged commit e1af249 into dev Feb 4, 2026
20 checks passed
@MichaIng MichaIng deleted the copilot/fix-mypy-errors branch February 4, 2026 00:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants